package com.ease.framework.gef4p.figures.impl.edge {
   import com.ease.framework.figures.IFigure;
   import com.ease.framework.gef.ui.ISelection;
   import com.ease.framework.gef4p.figures.ILabelFigure;
   import com.ease.framework.gef4p.figures.ILabelFigureBox;
   import com.ease.framework.gef4p.figures.INodeFigure;
   import com.ease.framework.gef4p.figures.edge.IEdgeAnchor;
   import com.ease.framework.gef4p.figures.edge.IEdgeAnchorListener;
   import com.ease.framework.gef4p.figures.edge.IEdgeFigure;
   import com.ease.framework.gef4p.figures.impl.LabelFigure;
   
   import flash.geom.Point;
   
   import mx.collections.ArrayCollection;
   import mx.core.IUIComponent;
   import mx.core.UIComponent;

   public class EdgeFigure extends UIComponent implements IEdgeFigure, ISelection, ILabelFigureBox, IEdgeAnchorListener {
      public var stManager:STNodeEdgeAnchorManager;
      public var arrawManager:EdgeArrawManager;
      public var anchorManager:BendAnchorManager;

      public function EdgeFigure(bendPoints:ArrayCollection = null) {
         super();
         if (bendPoints)
            _bends = bendPoints;
         stManager = new STNodeEdgeAnchorManager();
         arrawManager = new EdgeArrawManager();
         anchorManager = new BendAnchorManager();
         this.registerListener(stManager);
         this.registerListener(arrawManager);
         this.registerListener(anchorManager);
      }

      private var _source:INodeFigure;
      private var _target:INodeFigure;

      public function get source():INodeFigure {
         return _source;
      }

      public function set source(s:INodeFigure):void {
         _source = s;
      }

      public function get target():INodeFigure {
         return _target;
      }

      public function set target(t:INodeFigure):void {
         _target = t;
      }

      [Inspectable(defaultValue=false)]
      private var _isSelected:Boolean = false;

      //子类可以自行实现自己的连线样式
      protected var defaultBase:EdgeStyle = new EdgeStyle();
      protected var selectedBase:EdgeStyle = new EdgeStyle(0x0000FF, 3);
      public var currentBase:EdgeStyle = defaultBase;

      public function select():void {
         _isSelected = true;
         currentBase = selectedBase;
         if (listeners.length > 0) {
            for each (var listener:AbstractEdgeListener in listeners) {
               listener.select(this);
            }
         }
         invalidateDisplayList();
      }

      public function deselect():void {
         drawFocus(false);
         _isSelected = false;
         currentBase = defaultBase;
         if (listeners.length > 0) {
            for each (var listener:AbstractEdgeListener in listeners) {
               listener.select(this);
            }
         }
         this.invalidateDisplayList();
         getLabelFigure().isSelected = false;
      }

      public function get isSelected():Boolean {
         return _isSelected;
      }

      //----------------------------------------------拐点和操作点信息
      //记录当前Edge上的Bend节点
      protected var _bends:ArrayCollection = new ArrayCollection(); //用于建立连接线的所有的坐标的

      public function getSourceBend():Bend {
         for each (var bend:Bend in bends) {
            if (bend.getFront() == null) {
               return bend;
            }
         }
         return null;
      }

      public function getTargetBend():Bend {
         for each (var bend:Bend in bends) {
            if (bend.getNext() == null) {
               return bend;
            }
         }
         return null;
      }

      public function setSourceBend(x:Number, y:Number):Bend {
         var source:Bend = getSourceBend();
         if (source == null) {
            source = new Bend();
            var next:Bend = getTargetBend();
            if (next == null) {
               next = new Bend();
               bends.addItem(next);
            }
            else {
               while (next.getFront() != null) {
                  next = next.getFront();
               }
            }

            if (next != null) {
               source.setNext(next);
               next.setFront(source);
            }
            bends.addItem(source);
         }
         source.x = x;
         source.y = y;
         return source;
      }

      public function setTargetBend(x:Number, y:Number):Bend {
         var target:Bend = getTargetBend();
         if (target == null) {
            target = new Bend();
            var front:Bend = getSourceBend();
            if (source == null) {
               front = new Bend();
               bends.addItem(front);
            }
            else {
               while (front.getNext() != null) {
                  front = front.getNext();
               }
            }

            if (front != null) {
               front.setNext(target);
               target.setFront(front);
            }
            bends.addItem(target);
         }
         target.x = x;
         target.y = y;
         return target;
      }

      public function get bends():ArrayCollection {
         return _bends;
      }

      override protected function createChildren():void {
         super.createChildren();
         if (listeners.length > 0) {
            for each (var listener:AbstractEdgeListener in listeners) {
               listener.beforeCreateChildren(this);
            }
         }

         doCreateChildren();

         if (listeners.length > 0) {
            for each (listener in listeners) {
               listener.afterCreateChildren(this);
            }
         }
      }

      override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void {
         super.updateDisplayList(unscaledWidth, unscaledHeight);

         if (listeners.length > 0) {
            for each (var listener:AbstractEdgeListener in listeners) {
               listener.beforeDrawing(this);
            }
         }
         checkSourceTargetBends();
         drawing();

         if (listeners.length > 0) {
            for each (listener in listeners) {
               listener.afterDrawing(this);
            }
         }
      }


      /**
       * 这个方法放在绘制图元之前处理开始节点位置和结束节点的具体位置
       *
       *
       */
      protected function checkSourceTargetBends():void {

         if (source == null || target == null || source == target) {
            return;
         }

         var spoint:Point = findGlobalPoint(source);
         var tpoint:Point = findGlobalPoint(target);

         var sourceX:Number = spoint.x + source.width / 2;
         var sourceY:Number = spoint.y + source.height / 2;
         var targetX:Number = tpoint.x + target.width / 2;
         var targetY:Number = tpoint.y + target.height / 2;

         var sourceBend:Bend = setSourceBend(sourceX, sourceY);
         var targetBend:Bend = setTargetBend(targetX, targetY);

         if (sourceX == targetX && sourceY == targetY) {
            return;
         }
         var result:Bend = findBorderBends(source, sourceBend.getNext());
         setSourceBend(result.x, result.y);
         result = findBorderBends(target, targetBend.getFront());
         setTargetBend(result.x, result.y);
      }

      private function findBorderBends(node:IUIComponent, toBend:Bend):Bend {
         var spoint:Point = findGlobalPoint(node);

         var result:Bend = new Bend();
         result.x = spoint.x + node.width / 2;
         result.y = spoint.y + node.height / 2;

         var x1:Number = result.x + ((toBend.x - result.x) / Math.abs(toBend.x - result.x)) * node.width / 2;
         var y1:Number = result.y + ((toBend.y - result.y) / Math.abs(toBend.x - result.x)) * node.width / 2;
         var x2:Number = result.x + ((toBend.x - result.x) / Math.abs(toBend.y - result.y)) * node.height / 2;
         var y2:Number = result.y + ((toBend.y - result.y) / Math.abs(toBend.y - result.y)) * node.height / 2;

         if ((x2 <= (spoint.x + node.width) && x2 >= spoint.x) && ((y2 >= spoint.y - 1 && y2 <= spoint.y + 1) || (y2 >= spoint.y + node.height - 1 && y2 <= spoint.y + node.height + 1))) {
            result.x = x2;
            result.y = y2;
         }
         else /*if((x1 == node.x + node.width || x1 == node.x ) && (y1 <= (node.y + node.height) && y1 >= node.y))*/ {
            result.x = x1;
            result.y = y1;
         }
         return result;
      }



      public function doCreateChildren():void {
         if (source == null || target == null) {
            return;
         }

         createBends();

         checkSourceTargetBends();

         for each (var bend:Bend in bends) {
            if (!this.contains(bend))
               addChild(bend);
         }
         //Label相关的
         setLabelFigure(new LabelFigure())
         addChild(labelShow as UIComponent);
         labelShow.editWidth = 50;
         labelShow.editHeight = 30;
         labelShow.visible = false;
         UIComponent(this.getLabelFigure()).validateNow();
      }


      protected function createBends():void {
         if (bends.length < 2) {
            bends.removeAll();
            if (source == target) {
               //创建自连线的拐点
               createSelfLoop();
            }
            else {
               //创建起始到终结的连线
               createNewLine();
            }

         }
      }

      /**
       * 创建自连线的拐点
       *
       */
      protected function createSelfLoop():void {
         var spoint:Point = findGlobalPoint(source);

         var bend1:Bend = new Bend();
         bend1.x = spoint.x + source.width;
         bend1.y = spoint.y - source.height / 2;

         var bend2:Bend = new Bend();
         bend2.x = bend1.x + 150;
         bend2.y = bend1.y;
         bend1.setNext(bend2);
         bend2.setFront(bend1);

         var bend3:Bend = new Bend();
         bend3.x = bend2.x;
         bend3.y = spoint.y - 150;
         bend2.setNext(bend3);
         bend3.setFront(bend2);

         var bend4:Bend = new Bend();
         bend4.x = spoint.x + source.width / 2;
         bend4.y = bend3.y;
         bend3.setNext(bend4);
         bend4.setFront(bend3);

         var bend5:Bend = new Bend();
         bend5.x = bend4.x;
         bend5.y = spoint.y;
         bend4.setNext(bend5);
         bend5.setFront(bend4);

         bends.addItem(bend1);
         bends.addItem(bend2);
         bends.addItem(bend3);
         bends.addItem(bend4);
         bends.addItem(bend5);
      }

      /**
       *
       * 首次创建两个图元之间的连线
       *
       */
      protected function createNewLine():void {

         var spoint:Point = findGlobalPoint(source);
         var tpoint:Point = findGlobalPoint(target);

         var bend1:Bend = new Bend();
         var bend2:Bend = new Bend();
         bend1.setNext(bend2);
         bend2.setFront(bend1);

         bend1.x = spoint.x + source.width / 2;
         bend1.y = spoint.y + source.height / 2;

         bend2.x = tpoint.x + target.width / 2;
         bend2.y = tpoint.y + target.height / 2;
         bends.addItem(bend1);
         bends.addItem(bend2);
      }


      public function drawing():void {
         graphics.clear();
         if (bends.length >= 2) {
            var first:Bend = getSourceBend();

            while (first != null) {
               var next:Bend = first.getNext();
               if (next == null) {
                  break;
               }

               graphics.lineStyle(10, 0xFFFFFF, 0.1);
               graphics.moveTo(first.x, first.y - 1);
               graphics.lineTo(next.x, next.y - 1);

               graphics.lineStyle(10, 0xFFFFFF, 0.1);
               graphics.moveTo(first.x + 2, first.y + 2);
               graphics.lineTo(next.x + 2, next.y + 2);

               graphics.lineStyle(currentBase.width, currentBase.color, 1.2, true);

               var ffPoint:Point = findCurvePoint(first, next);
               if (first.getFront() != null && !(Math.abs(first.getFront().x - first.x) < 8 && Math.abs(first.getFront().y - first.y) < 8) && !(Math.abs(first.x - next.x) < 8 && Math.abs(first.y - next.y) < 8)) {
                  graphics.moveTo(first.x - ffPoint.x, first.y - ffPoint.y);
               }
               else {
                  graphics.moveTo(first.x, first.y);
               }

               var nnPoint:Point = findCurvePoint(next, next.getNext());

               var nn:Bend = next.getNext();
               if (nnPoint == null || (Math.abs(next.x - nn.x) < 8 && Math.abs(next.y - nn.y) < 8) || (Math.abs(first.x - next.x) < 8 && Math.abs(first.y - next.y) < 8)) { //直接连线，不需要弧度
                  graphics.lineTo(next.x, next.y);

               }
               else { //需要计算弧度
                  graphics.lineTo(next.x + ffPoint.x, next.y + ffPoint.y);
                  graphics.moveTo(next.x + ffPoint.x, next.y + ffPoint.y);
                  graphics.curveTo(next.x, next.y, next.x - nnPoint.x, next.y - nnPoint.y);
               }
               first = next;
            }
         }
      }

      /**
       * 获取节点差值，这里的返回值point只是用来存储xy值的容器
       *
       */
      private function findCurvePoint(from:Bend, _to:Bend):Point {
         if (from == null || _to == null) {
            return null;
         }
         var x:Number = from.x - _to.x;
         var y:Number = from.y - _to.y;
         var z:Number = Math.sqrt(x * x + y * y);
         var ll:Number = 6;
         var xx:Number = ll * x / z;
         var yy:Number = ll * y / z;
         var point:Point = new Point();
         point.x = xx;
         point.y = yy;
         return point;
      }


      public function refresh():void {
         if (listeners.length > 0) {
            for each (var listener:AbstractEdgeListener in listeners) {
               listener.beforeRefresh(this);
            }
         }

         doRefresh();

         if (listeners.length > 0) {
            for each (listener in listeners) {
               listener.afterRefresh(this);
            }
         }
         invalidateDisplayList();
      }

      public function doRefresh():void {
      }


      /**
       * 此方法用于校验在Bend被拖拽后，相邻的折线是否会合并.
       * 其实就是去掉冗余的Bend Point
       **/
      public function mergeBendofLine(bend:Bend):Boolean {

         var tmp_s_bend:Bend = bend.getFront();
         var tmp_t_bend:Bend = bend.getNext();
         if (tmp_s_bend == null || tmp_t_bend == null) {
            return false;
         }

         var angle_1:Number = Math.atan2(bend.y - tmp_s_bend.y, bend.x - tmp_s_bend.x);
         var angle_2:Number = Math.atan2(tmp_t_bend.y - tmp_s_bend.y, tmp_t_bend.x - tmp_s_bend.x);

         angle_1 = angle_1 * (180 / Math.PI);
         angle_2 = angle_2 * (180 / Math.PI);

         var tmpN:Number = angle_2 - angle_1;

         if (-8 < tmpN && tmpN < 8) {
            tmp_s_bend.setNext(tmp_t_bend)
            tmp_t_bend.setFront(tmp_s_bend);
            bend.setFront(null);
            bend.setNext(null);

            bends.removeItemAt(bends.getItemIndex(bend));
            this.removeChild(bend);
            return true;
         }
         return false;
      }


      public function clean():void {
         graphics.clear();
         if (listeners.length > 0) {
            for each (var listener:AbstractEdgeListener in listeners) {
               listener.clean(this);
            }
         }
         this.visible = false;
      }


      private var listeners:ArrayCollection = new ArrayCollection();


      public function registerListener(listener:AbstractEdgeListener):void {
         if (listener != null) {
            listeners.addItem(listener);
         }
      }

      public function removeListener(listener:AbstractEdgeListener):void {
         var index:int = listeners.getItemIndex(listener);
         if (index >= 0) {
            listeners.removeItemAt(index);
         }
      }

      public function clearListeners():void {
         listeners.removeAll();
      }


      //----------------------------------------------监听所有的anchor对象上的操作

      public function archorMoved(anchor:IEdgeAnchor):void {

      }



      public function findFigureAt(stageX:Number, stageY:Number):IFigure {
         if (labelShow.hitTestPoint(stageX, stageY, true)) {
            return labelShow;
         }
         else {
            return this;
         }
      }

      private var labelShow:ILabelFigure; //显示label的对象

      public function getLabelFigure():ILabelFigure {
         if (labelShow == null) {
            setLabelFigure(new LabelFigure());
         }
         return labelShow;
      }

      public function setLabelFigure(figure:ILabelFigure):void {
         labelShow = figure;
         figure.setContainer(this);
      }

      protected function findGlobalPoint(node:IUIComponent):Point {

         var point:Point = node.parent.localToGlobal(new Point(node.x, node.y));
         if (parent) {
            point = parent.globalToLocal(point);
         }
         return point;
      }
   }
}